跳到主要内容

为什么spring boot 3参数名称解析要废弃LocalVariableTableParameterNameDiscoverer

背景

spring boot 2.x我们都知道spring boot中想要获取参数名称的解析方式主要有如下几种

参数名解析方式特点
LocalVariableTableParameterNameDiscoverer解析字节码中的局部变量表不依赖 -parameters,但受编译器优化影响,JDK 9+ 可能失效
StandardReflectionParameterNameDiscoverer基于 -parameters 编译选项性能好,推荐使用,但需要启用 -parameters 编译选项
DefaultParameterNameDiscoverer优先使用StandardReflectionParameterNameDiscoverer,如果失败则使用LocalVariableTableParameterNameDiscoverer默认解析器,优先使用 StandardReflection,失败时回退到字节码解析
KotlinReflectionParameterNameDiscoverer基于 Kotlin 反射 APIKotlin 项目推荐使用,但不支持 Java 项目
PrioritizedParameterNameDiscoverer支持多个解析器的优先级组合灵活性强,适用于自定义解析逻辑。

用的比较多的还是DefaultParameterNameDiscovererLocalVariableTableParameterNameDiscoverer

因为很多人和很多项目都不知道-parameters这个编译选项,也不知道如何开启,所以很多项目都是使用LocalVariableTableParameterNameDiscoverer来解析参数名称

废弃LocalVariableTableParameterNameDiscoverer的前奏

如果我们升级到spring boot 3.0相关的版本,我们如果继续使用LocalVariableTableParameterNameDiscoverer来解析参数名称,会发现如下的警告

22-11-30 17:39:11.513 WARN [main LocalVariableTableParameterNameDiscoverer.inspectClass:123]Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer

这个警告就是未来会废弃掉基于字节码进行参数名解析,即LocalVariableTableParameterNameDiscoverer类,目前是一个过渡版本,还没有删除LocalVariableTableParameterNameDiscoverer

如果使用了LocalVariableTableParameterNameDiscoverer进行参数名解析需要修改为基于-parameters编译选项解析,因为之后的版本会删除LocalVariableTableParameterNameDiscoverer

何时废弃LocalVariableTableParameterNameDiscoverer

经过spring-framework-issues-29559spring-framework-pr-29531的讨论

最终在spring-framework-6.1.0完全删除掉LocalVariableTableParameterNameDiscoverer

为什么废弃LocalVariableTableParameterNameDiscoverer

其实早在issues-29559就进行过讨论为什么要废弃LocalVariableTableParameterNameDiscoverer

主要原因还是因为LocalVariableTableParameterNameDiscoverer是因为其依赖字节码实现细节,存在兼容性问题,编译成Native Image运行在GraalVM上不起作用

如何替换LocalVariableTableParameterNameDiscoverer

由于LocalVariableTableParameterNameDiscoverer被删除,所以我们需要使用StandardReflectionParameterNameDiscoverer来替换LocalVariableTableParameterNameDiscoverer进行参数名解析

StandardReflectionParameterNameDiscoverer是基于-parameters编译选项的,所以我们需要在maven打包工具中添加-parameters编译选项

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

核心配置是

                <configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>

如何验证是否生效

验证方式很简单,可以写一个简单的demo进行验证

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class ParameterExample {

public void exampleMethod(String param1, int param2) {
}

public static void main(String[] args) {
Method method = ParameterExample.class.getDeclaredMethods()[1];
for (Parameter parameter : method.getParameters()) {
System.out.println("小奏技术 Parameter name: " + parameter.getName());
}
}
}
  • 添加-parameters前输出

小奏技术 Parameter name: arg0 小奏技术 Parameter name: arg1

可以看到获取不到参数名

  • 添加-parameters后输出

小奏技术 Parameter name: param1 小奏技术 Parameter name: param2

可以看到获取到了真实的参数名

总结

spinrg boot 3.x高一点点的版本就废弃掉了LocalVariableTableParameterNameDiscoverer(基于字节码技术)方式的参数名解析

废弃原因主要是因为LocalVariableTableParameterNameDiscoverer是因为其依赖字节码实现细节,存在兼容性问题,编译成Native Image运行在GraalVM上不起作用

我们在进行替换的时候需要注意,需要在maven打包工具中添加-parameters编译选项,不然使用StandardReflectionParameterNameDiscoverer也是获取不到参数名的